package cn.edu.xmu.oomall.liquidation.service;

import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.oomall.liquidation.dao.LiquidationDao;
import cn.edu.xmu.oomall.liquidation.model.bo.ExpenditureItem;
import cn.edu.xmu.oomall.liquidation.model.bo.Liquidation;
import cn.edu.xmu.oomall.liquidation.model.bo.Liquidation.LiquidationState;
import cn.edu.xmu.oomall.liquidation.model.po.ExpenditureItemPoExample;
import cn.edu.xmu.oomall.liquidation.model.po.LiquidationPo;
import cn.edu.xmu.oomall.liquidation.model.po.LiquidationPoExample;
import cn.edu.xmu.oomall.liquidation.model.po.RevenueItemPoExample;
import cn.edu.xmu.oomall.liquidation.model.vo.LiquidationStateRetVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.awt.color.ICC_Profile;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class LiquidationService {
    @Autowired
    private LiquidationDao liquidationDao;

    public ReturnObject getAllLiquidationStates() {
        List<LiquidationStateRetVo> list = new ArrayList<>();

        for (LiquidationState state : LiquidationState.values()) {
            LiquidationStateRetVo stateRetVo = new LiquidationStateRetVo(state.getCode(), state.getDescription());
            list.add(stateRetVo);
        }
        return new ReturnObject(list);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getSimpleLiquidation(Long shopId, LocalDateTime beginDate, LocalDateTime endDate, Boolean state, Integer page, Integer pageSize) {
        return liquidationDao.getSimpleLiquidation(shopId, beginDate, endDate, state, page, pageSize);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getLiquidationById(Long shopId, Long id) {
        ReturnObject returnObject = liquidationDao.getLiquidationById(id);

        if (returnObject.getCode() == ReturnNo.OK) {
            Liquidation liquidation = (Liquidation) returnObject.getData();
            // 判断是否可以查询这个清算单
            if (shopId != 0 && !shopId.equals(liquidation.getShopId())) {
                returnObject =  new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE);
            }
        }

        return returnObject;
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getRevenueItem(Long shopId, Long orderId, Long productId, Long liquidationId, Integer page, Integer pageSize) {
        RevenueItemPoExample revenueItemPoExample = new RevenueItemPoExample();
        RevenueItemPoExample.Criteria criteria = revenueItemPoExample.createCriteria();
        // 因为shopId一定存在，所以不用判断是否查询了别的商铺的信息
        if (shopId != 0) {
            criteria.andShopIdEqualTo(shopId);
        }
        Optional.ofNullable(orderId).ifPresent(x -> criteria.andOrderIdEqualTo(x));
        Optional.ofNullable(productId).ifPresent(x -> criteria.andProductIdEqualTo(x));
        Optional.ofNullable(liquidationId).ifPresent(x -> criteria.andLiquidIdEqualTo(liquidationId));
        return liquidationDao.getRevenueItemUsePage(revenueItemPoExample, page, pageSize);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getExpenditure(Long shopId, Long orderId, Long productId, Long liquidationId, Integer page, Integer pageSize) {
        ExpenditureItemPoExample expenditureItemPoExample = new ExpenditureItemPoExample();
        ExpenditureItemPoExample.Criteria criteria = expenditureItemPoExample.createCriteria();
        // 因为shopId一定存在，所以不用判断是否查询了别的商铺的信息
        if (shopId != 0) {
            criteria.andShopIdEqualTo(shopId);
        }
        Optional.ofNullable(orderId).ifPresent(x -> criteria.andOrderIdEqualTo(x));
        Optional.ofNullable(productId).ifPresent(x -> criteria.andProductIdEqualTo(x));
        Optional.ofNullable(liquidationId).ifPresent(x -> criteria.andLiquidIdEqualTo(liquidationId));
        return liquidationDao.getExpenditureUsePage(expenditureItemPoExample, page, pageSize);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getRevenueByExpenditureId(Long shopId, Long id) {
        // 先查Id对应的出账是否存在
        ReturnObject returnObject = liquidationDao.getExpenditureById(id);
        if (returnObject.getCode() != ReturnNo.OK) {
            return returnObject;
        }

        ExpenditureItem expenditureItem = (ExpenditureItem) returnObject.getData();
        // 判断是否可以查询这个清算单的进出账
        if (shopId != 0 && !shopId.equals(expenditureItem.getShopId())) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE);
        }
        return returnObject;
    }

    private List<Long> getLiquidationIdListByDate(LocalDateTime beginDate, LocalDateTime endDate) {
        LiquidationPoExample liquidationPoExample = new LiquidationPoExample();
        LiquidationPoExample.Criteria criteria = liquidationPoExample.createCriteria();
        Optional.ofNullable(beginDate).ifPresent(x -> criteria.andLiquidDateGreaterThanOrEqualTo(beginDate));
        Optional.ofNullable(endDate).ifPresent(x -> criteria.andLiquidDateLessThanOrEqualTo(endDate));
        List<Liquidation> liquidationList = (List<Liquidation>) liquidationDao.getLiquidation(liquidationPoExample).getData();

        List<Long> liquidationIdList = liquidationList.stream().map(Liquidation::getId).collect(Collectors.toList());
        return liquidationIdList;
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getCustomerAcquirePointChange(Long userId, LocalDateTime beginDate, LocalDateTime endDate,Integer page, Integer pageSize) {
        List<Long> liquidationIdList = getLiquidationIdListByDate(beginDate, endDate);

        RevenueItemPoExample revenueItemPoExample = new RevenueItemPoExample();
        RevenueItemPoExample.Criteria revenueCriteria = revenueItemPoExample.createCriteria();
        revenueCriteria.andSharerIdEqualTo(userId);
        revenueCriteria.andLiquidIdIn(liquidationIdList);
        revenueItemPoExample.setOrderByClause("gmt_create desc");
        return liquidationDao.getRevenueItemUsePage(revenueItemPoExample, page, pageSize);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getCustomerLostPointChange(Long userId, LocalDateTime beginDate, LocalDateTime endDate,Integer page, Integer pageSize) {
        List<Long> liquidationIdList = getLiquidationIdListByDate(beginDate, endDate);

        ExpenditureItemPoExample expenditureItemPoExample = new ExpenditureItemPoExample();
        ExpenditureItemPoExample.Criteria expenditureCriteria = expenditureItemPoExample.createCriteria();
        expenditureCriteria.andSharerIdEqualTo(userId);
        expenditureCriteria.andLiquidIdIn(liquidationIdList);
        expenditureItemPoExample.setOrderByClause("gmt_create desc");
        return liquidationDao.getExpenditureUsePage(expenditureItemPoExample, page, pageSize);
    }
}